﻿namespace Rosieks.Web.Flow.Fluent
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;
    using Rosieks.Web.Flow.Metadata;

    public class FluentTransitionRegister<TWebflowModel>
    {
        private WebflowModel model;
        private State state;
        private IList<TransitionConfiguration> configurations;

        public FluentTransitionRegister(WebflowModel model, State state)
        {
            this.model = model;
            this.state = state;
            this.configurations = new List<TransitionConfiguration>();
        }

        private TransitionConfiguration LastTransition
        {
            get
            {
                return this.configurations[this.configurations.Count - 1];
            }

            set
            {
                this.configurations[this.configurations.Count - 1] = value;
            }
        }

        public FluentTransitionRegister<TWebflowModel> Transition(string on)
        {
            return this.Transition(on, on);
        }

        public FluentTransitionRegister<TWebflowModel> Transition(string on, string to)
        {
            this.configurations.Add(new TransitionConfiguration(() => new Transition(on, this.model[to])));

            return this;
        }

        public FluentTransitionRegister<TWebflowModel> Configure(Action<Transition> action)
        {
            this.LastTransition.ConfigurationActions.Add(action);

            return this;
        }

        public FluentTransitionRegister<TWebflowModel> WithoutValidation()
        {
            return this.Configure(t => t.RequireValidModel = false);
        }

        public FluentTransitionRegister<TWebflowModel> If(Func<TWebflowModel, bool> condition)
        {
            return this.If((model, context) => condition(model));
        }

        public FluentTransitionRegister<TWebflowModel> If(Func<TWebflowModel, ControllerContext, bool> condition)
        {
            return this.Configure(t => t.ConditionObject = new LambdaCondition<TWebflowModel>(condition));
        }

        public FluentTransitionRegister<TWebflowModel> AsDefault()
        {
            return this.Configure(t => t.IsDefault = true);
        }

        public void Execute()
        {
            state.Transitions = this.configurations.Select(t => t.Execute()).ToArray();
        }

        private class TransitionConfiguration
        {
            private Func<Transition> initiator;
            
            public TransitionConfiguration(Func<Transition> initiator)
            {
                this.initiator = initiator;
                this.ConfigurationActions = new List<Action<Transition>>();
            }

            public List<Action<Transition>> ConfigurationActions { get; set; }

            public Transition Execute()
            {
                Transition transition = this.initiator();

                foreach (var action in this.ConfigurationActions)
                {
                    action(transition);
                }

                return transition;
            }
        }
    }
}
